#include "Input.h"

CInput* CInput::Instance = new CInput();

CInput::CInput()
{

}

CInput::~CInput()
{
}

int CInput::InitInput(HINSTANCE hInstance)
{
	HRESULT result;

	result = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&mDI, NULL);
	if (result != DI_OK) return 0;
	Trace(L"DirectInput has been created");

	result = mDI->CreateDevice(GUID_SysKeyboard, &mKeyboard, NULL);
	if (result != DI_OK) return 0;
	Trace(L"DirectInput keyboard has been created");

	return 1;
}

int CInput::InitKeyboard(HWND hWnd)
{
	HRESULT result;

	// Set the data format to "keyboard format" - a predefined data format 
	//
	// A data format specifies which controls on a device we
	// are interested in, and how they should be reported.
	//
	// This tells DirectInput that we will be passing an array
	// of 256 bytes to IDirectInputDevice::GetDeviceState.
	result = mKeyboard->SetDataFormat(&c_dfDIKeyboard);
	if (result != DI_OK) return 0;
	Trace(L"SetDataFormat for keyboard successfully");

	result = mKeyboard->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
	if (result != DI_OK) return 0;
	Trace(L"SetCooperativeLevel for keyboard successfully");

	// IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
	//
	// DirectInput uses unbuffered I/O (buffer size = 0) by default.
	// If you want to read buffered data, you need to set a nonzero
	// buffer size.
	//
	// Set the buffer size to DINPUT_BUFFERSIZE (defined above) elements.
	//
	// The buffer size is a DWORD property associated with the device.
	DIPROPDWORD dipdw;
	dipdw.diph.dwSize = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj = 0;
	dipdw.diph.dwHow = DIPH_DEVICE;
	dipdw.dwData = KEYBOARD_BUFFER_SIZE;
	mKeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);
	if (result != DI_OK) return 0;
	Trace(L"SetProperty for keyboard successfully");

	result = mKeyboard->Acquire();
	if (result != DI_OK) return 0;
	Trace(L"Keyboard has been acquired successfully");

	return 1; 
}

void CInput::ProcessKeyboard() 
{
	if (mKeyboard->GetDeviceState(sizeof(mKeyStates), (LPVOID)mKeyStates) != DI_OK)
	{
		mKeyboard->Acquire();
		mKeyboard->GetDeviceState(sizeof(mKeyStates), (LPVOID)mKeyStates);
	}
}

void CInput::Update()
{
	//poll state of the keyboard
	mKeyboard->Poll();
	if (!SUCCEEDED(mKeyboard->GetDeviceState(256, (LPVOID)&mKeyStates)))
	{
		//keyboard device lost, try to re-acquire
		mKeyboard->Acquire();
	}
	// Collect all buffered events
	DWORD dwElements = KEYBOARD_BUFFER_SIZE;
	HRESULT hr = mKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), mKeyEvents, &dwElements, 0);

	// Scan through all data, check if the key is pressed or released
	for (DWORD i = 0; i < dwElements; i++)
	{
		int KeyCode = mKeyEvents[i].dwOfs;
		int KeyState = mKeyEvents[i].dwData;
		if ((KeyState & 0x80) > 0)
			mKeyDown = KeyCode;
		else
			mKeyUP = KeyCode;
	}
}

int CInput::IsKeyDown(int keyCode)
{
	return (mKeyStates[keyCode] & 0x80) > 0;
}

int CInput::GetKeyDown()
{
	int keyDown = mKeyDown;
	mKeyDown = 0;
	return keyDown;
}

int CInput::GetKeyUp()
{
	int keyUp = mKeyUP;
	mKeyUP = 0;
	return keyUp;
}
